package com.zenjava.zendeploy.win;

import zom.zenjava.zendeploy.ZenDeployException;
import zom.zenjava.zendeploy.ZenDeployManager;
import zom.zenjava.zendeploy.model.ApplicationProfile;
import zom.zenjava.zendeploy.model.Dependency;
import zom.zenjava.zendeploy.model.DependencySet;
import zom.zenjava.zendeploy.model.JreReference;
import zom.zenjava.zendeploy.util.ArchiveUnzipper;
import zom.zenjava.zendeploy.util.FileDownloader;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

public class ZenDeployManagerWinImpl extends ZenDeployManager
{
    private final static Logger LOGGER = Logger.getLogger(ZenDeployManagerWinImpl.class.getName());

    protected boolean doUpgrade(File installationDir,
                                ApplicationProfile currentAppProfile,
                                ApplicationProfile updatedAppProfile, 
                                File updatedAppProfileFile)
    {
        // create a temp directory to download to (since Program Files has security restrictions)

        File tempDir;
        try
        {
            // Java doesn't let us create temp dirs easily so instead we create a
            // temp file then delete it and recreate as a directory
            tempDir = File.createTempFile("inst", "dir");
            tempDir.delete();
            tempDir.mkdir();
        }
        catch (IOException e)
        {
            throw new ZenDeployException("Unable to create a temporary working directory for download", e);
        }

        // check for a new JRE and download and unzip if needed

        if (!currentAppProfile.getJreReference().getVersion().equals(
                updatedAppProfile.getJreReference().getVersion()))
        {
            JreReference jreReference = updatedAppProfile.getJreReference();
            File tempJreFile = null;
            try
            {
                //publish("Updating JRE to version " + jreReference.getVersion());
                LOGGER.info(String.format("Updating JRE to version %s", jreReference.getVersion()));

                URL jreUrl = new URL(jreReference.getUrl());
                tempJreFile = File.createTempFile("jre", "zip");
                FileDownloader downloader = new FileDownloader(jreUrl, tempJreFile);
                downloader.download();

                File jreSubDir = new File(tempDir, "jre");
                jreSubDir.mkdir();
                ArchiveUnzipper unzipper = new ArchiveUnzipper(tempJreFile, new File(jreSubDir, jreReference.getVersion()));
                unzipper.unzip();
            }
            catch (IOException e)
            {
                throw new ZenDeployException(String.format("Error downloading and extracting JRE version '%s' from: %s",
                        jreReference.getVersion(), jreReference.getUrl()));
            }
            finally
            {
                if (tempJreFile != null)
                {
                    tempJreFile.delete();
                }
            }
        }

        // check for any new dependencies (e.g. JARs) and download as needed

        List<String> currentDependencies = new ArrayList<String>();
        for (DependencySet dependencySet : currentAppProfile.getDependencySet())
        {
            for (Dependency dependency : dependencySet.getDependencies())
            {
                String key = String.format("%s-%s", dependency.getId(), dependency.getVersion());
                currentDependencies.add(key);
            }
        }

        File baseDependencyDir = new File(tempDir, "app");
        baseDependencyDir.mkdir();
        for (DependencySet dependencySet : updatedAppProfile.getDependencySet())
        {
            for (Dependency dependency : dependencySet.getDependencies())
            {
                String key = String.format("%s-%s", dependency.getId(), dependency.getVersion());
                if (!currentDependencies.contains(key))
                {
                    String path = String.format("%s/%s", dependencySet.getBaseUrl(), dependency.getPath());
                    try
                    {
                        LOGGER.info(String.format("Downloading JAR from: %s", path));
                        File localFile = new File(baseDependencyDir, String.format("%s-%s.jar", dependency.getId(), dependency.getVersion()));
                        FileDownloader downloader = new FileDownloader(new URL(path), localFile);
                        downloader.download();
                    }
                    catch (IOException e)
                    {
                        throw new ZenDeployException(String.format(
                                "Error downloading updated dependency '%s' (version %s) from: %s",
                                dependency.getId(), dependency.getVersion(), path), e);
                    }
                }
            }
        }

        // move the new app-profile.xml file into the temp dir so it will be included in the install
        if (!updatedAppProfileFile.renameTo(new File(tempDir, "app-profile.xml")))
        {
            throw new ZenDeployException("Unable to create new 'app-profile.xml' with updated launch details");
        }

        // copy everything to the install directory - we use an external process here to gain admin rights since by
        // default windows won't let us write to the 'Program Files' directory
        WinUacFriendlyFileMover fileMover = new WinUacFriendlyFileMover();
        String currentJrePath = String.format("jre\\%s", currentAppProfile.getJreReference().getVersion());
        fileMover.moveFilesUacFriendly(currentAppProfile, installationDir, tempDir);

        // delete the temp directory
        tempDir.delete();
        
        return true;
    }

    public void restart() throws ZenDeployException
    {
        try
        {
            File installationDirectory = getInstallationDirectory();
            String command = String.format("%s\\launch.exe", installationDirectory.getAbsolutePath());
            ProcessBuilder builder = new ProcessBuilder(command);
            builder.directory(installationDirectory);
            builder.start();
            System.exit(0);
        }
        catch (IOException e)
        {
            throw new ZenDeployException("Error restarting application", e);
        }
    }
}
